home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / Dev / SmallTalk / msttree.c < prev    next >
C/C++ Source or Header  |  1995-08-25  |  18KB  |  793 lines

  1. /***********************************************************************
  2.  *
  3.  *    Semantic Tree manipulation module.
  4.  *
  5.  ***********************************************************************/
  6.  
  7. /***********************************************************************
  8.  *
  9.  * Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc.
  10.  * Written by Steve Byrne.
  11.  *
  12.  * This file is part of GNU Smalltalk.
  13.  *
  14.  * GNU Smalltalk is free software; you can redistribute it and/or modify it
  15.  * under the terms of the GNU General Public License as published by the Free
  16.  * Software Foundation; either version 1, or (at your option) any later 
  17.  * version.
  18.  * 
  19.  * GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
  20.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
  21.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  22.  * more details.
  23.  * 
  24.  * You should have received a copy of the GNU General Public License along with
  25.  * GNU Smalltalk; see the file COPYING.  If not, write to the Free Software
  26.  * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  
  27.  *
  28.  ***********************************************************************/
  29.  
  30.  
  31. /*
  32.  *    Change Log
  33.  * ============================================================================
  34.  * Author      Date       Change 
  35.  * sbyrne    30 Dec 88      Created.
  36.  *
  37.  */
  38.  
  39.  
  40. #include "mst.h"
  41. #include "mstsym.h"
  42. #include "msttree.h"
  43. #include <stdio.h>
  44.  
  45. char    *nilName = "(nil)"; /* how to print nil */
  46.  
  47. Boolean hadError = false;
  48.  
  49. static TreeNode makeMethodNode(), makeListNode(), makeExprNode();
  50. static TreeNode makeTreeNode();
  51. static OOP    makeUnarySelector(), makeBinarySelector();
  52. static void    freeNode(), freeMethodNode(), freeExprNode(), freeListNode(),
  53.           freeConstNode();
  54. static void    printMethodNode(), printExprNode(), printListNode(),
  55.           printConstNode(), printNodeType(), indent(), printSelector();
  56.  
  57. #ifdef not_used /* Sat Jan 19 14:56:15 1991 */
  58. /**/static OOP    *binopSymbols[] = { /* indexed by binop */
  59. /**/  &nilSymbol,            /* there is no zeroth entry  */
  60. /**/  &plusSymbol,
  61. /**/  &minusSymbol,
  62. /**/  ×Symbol,
  63. /**/  ÷Symbol,
  64. /**/  &lessThanSymbol,
  65. /**/  &greaterThanSymbol,
  66. /**/  &equalSymbol,
  67. /**/  ¬EqualSymbol,
  68. /**/  &lessEqualSymbol,
  69. /**/  &greaterEqualSymbol,
  70. /**/  &integerDivideSymbol,
  71. /**/  &remainderSymbol,
  72. /**/  &sameObjectSymbol,
  73. /**/  ¬SameObjectSymbol,
  74. /**/  &orSymbol,
  75. /**/  &andSymbol
  76. /**/};
  77. #endif /* not_used Sat Jan 19 14:56:15 1991 */
  78.  
  79. /* Used only for printing tree node names when debugging */
  80. static char *nodeTypeNames[] = {
  81.   "methodNodeType",         /* methodNodeType */
  82.   "unaryExprType",         /* unaryExprType */
  83.   "binaryExprType",         /* binaryExprType */
  84.   "keywordExprType",         /* keywordExprType */
  85.   "variableNodeType",         /* variableNodeType */
  86.   "keywordListType",         /* keywordListType */
  87.   "variableListType",         /* variableListType */
  88.   "statementListType",         /* statementListType */
  89.   "returnExprType",         /* returnExprType */
  90.   "assignExprType",         /* assignExprType */
  91.   "constExprType",         /* constExprType */
  92.   "symbolNodeType",         /* symbolNodeType */
  93.   "arrayEltListType",         /* arrayEltListType */
  94.   "blockNodeType",         /* blockNodeType */
  95.   "cascadedMessageNodeType",     /* cascadedMessageNodeType */
  96.   "messageListType"         /* messageListType */
  97. };
  98.  
  99.  
  100.  
  101. /*
  102.  *    TreeNode makeArrayElt(elt)
  103.  *
  104.  * Description
  105.  *
  106.  *    Create an element of an array constant, which is a list type object.
  107.  *    Return the element with the next field NILed out.
  108.  *
  109.  * Inputs
  110.  *
  111.  *    elt   : TreeNode array element to use
  112.  *
  113.  * Outputs
  114.  *
  115.  *    TreeNode of type arrayEltListType that contains "elt".
  116.  */
  117. TreeNode makeArrayElt(elt)
  118. TreeNode elt;
  119. {
  120.   return (makeListNode(arrayEltListType, nil, elt));
  121. }
  122.  
  123.   
  124. /*
  125.  *    TreeNode makeMethod(selectorExpr, temporaries, primitiveIndex,
  126.  *                statements)
  127.  *
  128.  * Description
  129.  *
  130.  *    Create a method node.  The method will be invoked by a selector dervied
  131.  *    from "selectorExpr", it has (possibly nil) "temporaries" variables,
  132.  *    and contains "statements".  If the method has a primitive associated
  133.  *    with it, then "primitiveIndex" is non-zero.
  134.  *
  135.  * Inputs
  136.  *
  137.  *    selectorExpr: 
  138.  *        Expression that's to be the selector for this method.
  139.  *    temporaries: 
  140.  *        Possibly nil list of temporary variable names.
  141.  *    primitiveIndex:
  142.  *        Integer.  If non-zero, this method has associated with it
  143.  *        a primitive with index "primitiveIndex".
  144.  *    statements: 
  145.  *        List of statements that comprise the procedural part of this
  146.  *        method.
  147.  *
  148.  * Outputs
  149.  *
  150.  *    TreeNode of type methodNodeType.
  151.  */
  152. TreeNode makeMethod(selectorExpr, temporaries, primitiveIndex, statements)
  153. TreeNode selectorExpr, temporaries, statements;
  154. int    primitiveIndex;
  155. {
  156.   return (makeMethodNode(methodNodeType, selectorExpr,
  157.              temporaries, primitiveIndex, statements));
  158. }
  159.  
  160.  
  161. /*
  162.  *    TreeNode makeCascadedMessage(messageExpr, cascadedMessages)
  163.  *
  164.  * Description
  165.  *
  166.  *    Creates a node for holding a list of cascaded messages (basically an
  167.  *    Expr node that isn't using its symbol.  "messageExpr" is the expression
  168.  *    invoke first as it computes the receiver.  Then the remaining cascaded
  169.  *    messages are sent to that receiver.
  170.  *
  171.  * Inputs
  172.  *
  173.  *    messageExpr: 
  174.  *        Evaluates to the receiver of the cascaded messages
  175.  *    cascadedMessages: 
  176.  *        List of the cascaded messages to send to the receiver.
  177.  *
  178.  * Outputs
  179.  *
  180.  *    TreeNode of type cascadedMessageTypeNode.
  181.  */
  182. TreeNode makeCascadedMessage(messageExpr, cascadedMessages)
  183. TreeNode messageExpr, cascadedMessages;
  184. {
  185.   return (makeExprNode(cascadedMessageNodeType, messageExpr, nil,
  186.                cascadedMessages));
  187. }
  188.  
  189.  
  190. TreeNode makeUnaryExpr(receiver, unarySelectorExpr)
  191. TreeNode receiver;
  192. char     *unarySelectorExpr;
  193. {
  194.   OOP        selector;
  195.  
  196.   selector = makeUnarySelector(unarySelectorExpr);
  197.   return (makeExprNode(unaryExprType, receiver, selector, nil));
  198. }
  199.  
  200. TreeNode internBinOP(binaryOp)
  201. char    *binaryOp;
  202. {
  203.   return (makeExprNode(symbolNodeType, nil, makeBinarySelector(binaryOp),
  204.                nil));
  205. }
  206.  
  207. TreeNode internIdent(ident)
  208. char    *ident;
  209. {
  210.   return (makeExprNode(symbolNodeType, nil, internString(ident), nil));
  211. }
  212.  
  213. TreeNode makeStatementList(expression, statements)
  214. TreeNode expression, statements;
  215. {
  216.   return (makeExprNode(statementListType, expression, nilOOP, statements));
  217. }
  218.  
  219. TreeNode makeReturn(expression)
  220. TreeNode expression;
  221. {
  222.   return (makeExprNode(returnExprType, expression, nilOOP, nil));
  223. }
  224.  
  225. TreeNode makeKeywordExpr(receiver, keywordMessage)
  226. TreeNode receiver, keywordMessage;
  227. {
  228.   return (makeExprNode(keywordExprType, receiver, nilOOP, keywordMessage));
  229. }
  230.  
  231. TreeNode makeAssign(variables, expression)
  232. TreeNode variables, expression;
  233. {
  234.   return (makeExprNode(assignExprType, variables, nilOOP, expression));
  235. }
  236.  
  237. TreeNode makeKeywordList(keyword, expression)
  238. char    *keyword;
  239. TreeNode expression;
  240. {
  241.   return (makeListNode(keywordListType, keyword, expression));
  242. }
  243.  
  244. /*
  245.  *    TreeNode makeVariableList(variable)
  246.  *
  247.  * Description
  248.  *
  249.  *    Given a variable tree node, this routine returns a variable list tree
  250.  *    node with a nil next link.  Actually, we rely on the fact that a
  251.  *    variable is represented as a tree node of type ListNode, so  all we do
  252.  *    is change the node tag to variableListType.
  253.  *
  254.  * Inputs
  255.  *
  256.  *    variable: 
  257.  *        Name of variable that's to be part of the list, TreeNode.
  258.  *
  259.  * Outputs
  260.  *
  261.  *    New TreeNode.
  262.  */
  263. TreeNode makeVariableList(variable)
  264. TreeNode variable;
  265. {
  266.   variable->nodeType = variableListType;
  267.   return (variable);
  268. }
  269.  
  270.  
  271. TreeNode makeBinaryExpr(receiver, binaryOp, argument)
  272. TreeNode receiver, argument;
  273. char    *binaryOp;
  274. {
  275.   OOP        selector;
  276.  
  277.   selector = makeBinarySelector(binaryOp);
  278.   return (makeExprNode(binaryExprType, receiver, selector, argument));
  279. }
  280.  
  281. TreeNode makeMessageList(messageElt)
  282. TreeNode messageElt;
  283. {
  284.   return (makeListNode(messageListType, nil, messageElt));
  285. }
  286.  
  287. /*
  288.  *    TreeNode makeBlock(temporaries, statements)
  289.  *
  290.  * Description
  291.  *
  292.  *    Creates a block tree node and returns it.
  293.  *
  294.  * Inputs
  295.  *
  296.  *    temporaries: 
  297.  *        Possibly nil list of temporary variable names to use for this
  298.  *        block 
  299.  *    statements: 
  300.  *        List of statements that are the procedure part of this block.
  301.  *
  302.  * Outputs
  303.  *
  304.  *    New tree node.
  305.  */
  306. TreeNode makeBlock(temporaries, statements)
  307. TreeNode temporaries, statements;
  308. {
  309.   return (makeMethodNode(blockNodeType, nil, temporaries, 0, statements));
  310. }
  311.  
  312. TreeNode makeVariable(name)
  313. char    *name;
  314. {
  315.   return (makeListNode(variableNodeType, name, nil));
  316. }
  317.  
  318.  
  319. TreeNode makeIntConstant(ival)
  320. long    ival;
  321. {
  322.   TreeNode     result;
  323.  
  324.   result = makeTreeNode(constExprType);
  325.   result->vConst.constType = intConst;
  326.   result->vConst.val.iVal = ival;
  327.  
  328.   return (result);
  329. }
  330.  
  331. TreeNode makeFloatConstant(fval)
  332. double    fval;
  333. {
  334.   TreeNode     result;
  335.  
  336.   result = makeTreeNode(constExprType);
  337.   result->vConst.constType = floatConst;
  338.   result->vConst.val.fVal = fval;
  339.  
  340.   return (result);
  341. }
  342.  
  343. TreeNode makeCharConstant(cval)
  344. char    cval;
  345. {
  346.   TreeNode     result;
  347.  
  348.   result = makeTreeNode(constExprType);
  349.   result->vConst.constType = charConst;
  350.   result->vConst.val.cVal = cval;
  351.  
  352.   return (result);
  353. }
  354.  
  355. TreeNode makeStringConstant(sval)
  356. char    *sval;
  357. {
  358.   TreeNode     result;
  359.  
  360.   result = makeTreeNode(constExprType);
  361.   result->vConst.constType = stringConst;
  362.   result->vConst.val.sVal = sval;
  363.  
  364.   return (result);
  365. }
  366.  
  367. TreeNode makeSymbolConstant(symbolNode)
  368. TreeNode symbolNode;
  369. {
  370.   TreeNode     result;
  371.  
  372.   result = makeTreeNode(constExprType);
  373.   result->vConst.constType = symbolConst;
  374.   if (symbolNode) {
  375.     result->vConst.val.symVal = symbolNode->vExpr.selector;
  376.     freeNode(symbolNode);
  377.   } else {
  378.     result->vConst.val.symVal = nilOOP;
  379.   }
  380.  
  381.   return (result);
  382. }
  383.  
  384. TreeNode makeArrayConstant(aval)
  385. TreeNode aval;
  386. {
  387.   TreeNode     result;
  388.  
  389.   result = makeTreeNode(constExprType);
  390.   result->vConst.constType = arrayConst;
  391.   result->vConst.val.aVal = aval;
  392.  
  393.   return (result);
  394. }
  395.  
  396.  
  397. /*
  398.  *    void addNode(n1, n2)
  399.  *
  400.  * Description
  401.  *
  402.  *    adds node "n2" onto a list of nodes headed by "n1".  "n1" contains
  403.  *    the address of the last "next" field in the chain, so storing "n2" into
  404.  *    there indirectly and then making that "next" field point to "n2"'s
  405.  *    "next" field works properly.
  406.  *
  407.  * Inputs
  408.  *
  409.  *    n1    : head of list of nodes, of type listNode.
  410.  *    n2    : node to be added, of type listNode.
  411.  *
  412.  */
  413. void addNode(n1, n2)
  414. TreeNode n1, n2;
  415. {
  416.   *(n1->vList.nextAddr) = n2;
  417.   n1->vList.nextAddr = n2->vList.nextAddr; /* since they're all created this
  418.                         * way anyway, we might as well
  419.                         * use it to our advantage */
  420. }
  421.  
  422. void freeTree(tree)
  423. TreeNode tree;
  424. {
  425.   if (tree == nil) {
  426.     return;
  427.   }
  428.  
  429.   switch (tree->nodeType) {
  430.   case methodNodeType:
  431.   case blockNodeType:
  432.     freeMethodNode(tree);
  433.     break;
  434.     
  435.   case symbolNodeType:
  436.   case unaryExprType:
  437.   case binaryExprType:
  438.   case keywordExprType:
  439.   case cascadedMessageNodeType:
  440.   case statementListType:
  441.   case returnExprType:
  442.   case assignExprType:
  443.     freeExprNode(tree);
  444.     break;
  445.     
  446.   case variableNodeType:
  447.   case keywordListType:
  448.   case variableListType:
  449.   case arrayEltListType:
  450.   case messageListType:
  451.     freeListNode(tree);
  452.     break;
  453.  
  454.   case constExprType:
  455.     freeConstNode(tree);
  456.     break;
  457.  
  458.   }
  459. }
  460.  
  461.  
  462.  
  463. /***********************************************************************
  464.  *
  465.  * Internal tree construction routines.
  466.  *
  467.  ***********************************************************************/
  468.  
  469.  
  470. static TreeNode makeMethodNode(nodeType, selectorExpr, temporaries,
  471.                    primitiveIndex, statements)
  472. NodeType nodeType;
  473. TreeNode selectorExpr, temporaries, statements;
  474. int    primitiveIndex;
  475. {
  476.   TreeNode    result;
  477.  
  478.   result = makeTreeNode(nodeType);
  479.   result->vMethod.selectorExpr = selectorExpr;
  480.   result->vMethod.temporaries = temporaries;
  481.   result->vMethod.primitiveIndex = primitiveIndex;
  482.   result->vMethod.statements = statements;
  483.   return (result);
  484. }
  485.  
  486. static TreeNode makeListNode(nodeType, name, value)
  487. NodeType nodeType;
  488. char    *name;
  489. TreeNode value;
  490. {
  491.   TreeNode result;
  492.  
  493.   result = makeTreeNode(nodeType);
  494.   result->vList.name = name;
  495.   result->vList.value = value;
  496.   result->vList.next = nil;
  497.   result->vList.nextAddr = &result->vList.next;
  498.   return (result);
  499. }
  500.  
  501. static TreeNode makeExprNode(nodeType, receiver, selector, expression)
  502. NodeType nodeType;
  503. TreeNode receiver, expression;
  504. OOP    selector;
  505. {
  506.   TreeNode result;
  507.  
  508.   result = makeTreeNode(nodeType);
  509.   result->vExpr.receiver = receiver;
  510.   result->vExpr.selector = selector;
  511.   result->vExpr.expression = expression;
  512.   return (result);
  513. }
  514.  
  515. static TreeNode makeTreeNode(nodeType)
  516. NodeType nodeType;
  517. {
  518.   TreeNode result;
  519.  
  520.   result = (TreeNode)malloc(sizeof(struct TreeNodeStruct));
  521.   result->nodeType = nodeType;
  522.   return (result);
  523. }
  524.  
  525. /* ### these should probably be moved over into the symbol table module, yes?*/
  526.  
  527. static OOP makeUnarySelector(name)
  528. char    *name;
  529. {
  530.   return (internString(name));
  531. }
  532.  
  533. static OOP makeBinarySelector(binaryOp)
  534. char    *binaryOp;
  535. {
  536.   return (internString(binaryOp));
  537. }
  538.  
  539. /***********************************************************************
  540.  *
  541.  * Internal tree destruction routines.
  542.  *
  543.  ***********************************************************************/
  544.  
  545. static void freeMethodNode(node)
  546. TreeNode node;
  547. {
  548.   freeTree(node->vMethod.selectorExpr);
  549.   freeTree(node->vMethod.temporaries);
  550.   freeTree(node->vMethod.statements);
  551.   freeNode(node);
  552. }
  553.  
  554. static void freeExprNode(node)
  555. TreeNode node;
  556. {
  557.   freeTree(node->vExpr.receiver);
  558.   freeTree(node->vExpr.expression);
  559.   freeNode(node);
  560. }
  561.  
  562. static void freeListNode(node)
  563. TreeNode node;
  564. {
  565.   freeTree(node->vList.value);
  566.   freeTree(node->vList.next);
  567.   if (node->vList.name) {
  568.     free(node->vList.name);
  569.   }
  570.  
  571.   freeNode(node);
  572. }
  573.  
  574. static void freeConstNode(node)
  575. TreeNode node;
  576. {
  577.   switch (node->vConst.constType) {
  578.   case intConst:
  579.   case floatConst:
  580.   case charConst:
  581.   case symbolConst:
  582.     /* these have no storage of their own */
  583.     break;
  584.  
  585.   case stringConst:
  586.     if (node->vConst.val.sVal) {
  587.       free(node->vConst.val.sVal);
  588.     } else {
  589.       errorf("Internal error: badly formed tree for string constant"); 
  590.     }
  591.     break;
  592.  
  593.   case arrayConst:
  594.     freeTree(node->vConst.val.aVal);
  595.     break;
  596.  
  597.   default:
  598.     errorf("Internal error: corrupted tree structure"); 
  599.   }
  600.  
  601.   freeNode(node);
  602. }
  603.  
  604.  
  605. static void freeNode(node)
  606. TreeNode node;
  607. {
  608.   free(node);
  609. }
  610.  
  611.  
  612. /***********************************************************************
  613.  *
  614.  *    Printing routines.
  615.  *
  616.  ***********************************************************************/
  617.  
  618.  
  619. void printTree(node, level)
  620. TreeNode node;
  621. int level;
  622. {
  623.   if (node == nil) {
  624.     indent(level);
  625.     printf("%s\n", nilName);
  626.     return;
  627.   }
  628.  
  629.   switch (node->nodeType) {
  630.   case methodNodeType:
  631.   case blockNodeType:
  632.     printMethodNode(node, level);
  633.     break;
  634.     
  635.   case symbolNodeType:
  636.   case unaryExprType:
  637.   case binaryExprType:
  638.   case keywordExprType:
  639.   case cascadedMessageNodeType:
  640.   case statementListType:
  641.   case returnExprType:
  642.   case assignExprType:
  643.     printExprNode(node, level);
  644.     break;
  645.     
  646.   case variableNodeType:
  647.   case keywordListType:
  648.   case variableListType:
  649.   case arrayEltListType:
  650.   case messageListType:
  651.     printListNode(node, level);
  652.     break;
  653.  
  654.   case constExprType:
  655.     printConstNode(node, level);
  656.     break;
  657.  
  658.   default:
  659.     errorf("Unknown tree note type %d\n", node->nodeType);
  660.   }
  661. }
  662.  
  663.  
  664. static void printListNode(node, level)
  665. TreeNode node;
  666. int level;
  667. {
  668.   printNodeType(node, level);
  669.   indent(level+1);
  670.   printf("name: %s\n", node->vList.name ? node->vList.name : nilName);
  671.   indent(level+1);
  672.   printf("value:\n");
  673.   printTree(node->vList.value, level+2);
  674.   indent(level+1);
  675.   printf("next:\n");
  676.   printTree(node->vList.next, level);
  677. }
  678.  
  679. static void printExprNode(node, level)
  680. TreeNode node;
  681. int level;
  682. {
  683.   printNodeType(node, level);
  684.   indent(level+1);
  685.   printf("selector: ");
  686.   if (!isNil(node->vExpr.selector)) {
  687.     printSelector(node->vExpr.selector);
  688.   } else {
  689.     printf("%s", nilName);
  690.   }
  691.   printf("\n");
  692.     
  693.   indent(level+1);
  694.   printf("receiver:\n");
  695.   printTree(node->vExpr.receiver, level+2);
  696.   /* ??? don't print the expression for unary type things, and don't print
  697.      the receiver for symbol nodes */
  698.   indent(level+1);
  699.   printf("expression:\n");
  700.   printTree(node->vExpr.expression, level+2);
  701. }
  702.  
  703. static void printMethodNode(node, level)
  704. TreeNode node;
  705. int level;
  706. {
  707.   printNodeType(node, level);
  708.   indent(level+1);
  709.   printf("selectorExpr: ");
  710.   printTree(node->vMethod.selectorExpr, level+2);
  711.   indent(level+1);
  712.   /* ??? don't print the temporaries label if there are no temporaries */
  713.   printf("temporaries:\n");
  714.   printTree(node->vMethod.temporaries, level+2);
  715.   indent(level+1);
  716.   printf("statements:\n");
  717.   printTree(node->vMethod.statements, level+2);
  718. }
  719.  
  720. static void printConstNode(node, level)
  721. TreeNode node;
  722. int level;
  723. {
  724.   indent(level);
  725.   switch (node->vConst.constType) {
  726.   case intConst:
  727.     printf("int: %ld\n", node->vConst.val.iVal);
  728.     break;
  729.  
  730.   case floatConst:
  731.     printf("float: %g\n", node->vConst.val.fVal);
  732.     break;
  733.  
  734.   case charConst:
  735.     printf("char: %c\n", node->vConst.val.cVal);
  736.     break;
  737.  
  738.   case stringConst:
  739.     printf("string: \"%s\"\n", node->vConst.val.sVal);
  740.     break;
  741.  
  742.   case symbolConst:
  743.     printf("symbol: ");
  744.     printSymbol(node->vConst.val.symVal);
  745.     printf("\n");
  746.     break;
  747.  
  748.   case arrayConst:
  749.     printf("array:\n");
  750.     printTree(node->vConst.val.aVal, level+1);
  751.     break;
  752.     
  753.   default:
  754.     errorf("Unknown constant type %d", node->vConst.constType);
  755.   }
  756. }
  757.  
  758.  
  759. static void printNodeType(node, level)
  760. TreeNode node;
  761. int level;
  762. {
  763.   indent(level);
  764.   printf("%s\n", nodeTypeNames[ENUM_INT(node->nodeType)]);
  765. }
  766.  
  767. /*
  768.  *    static void indent(level)
  769.  *
  770.  * Description
  771.  *
  772.  *    Indent the output by level*2 spaces.
  773.  *
  774.  * Inputs
  775.  *
  776.  *    level : Indentation level.  C integer.
  777.  *
  778.  */
  779. static void indent(level)
  780. int level;
  781. {
  782.   for (; level > 0; level--) {
  783.     printf("  ");
  784.   }
  785. }
  786.  
  787. static void printSelector(selector)
  788. OOP    selector;
  789. {
  790.   printSymbol(selector);
  791. }
  792.  
  793.